//
//  CalendarRange.m
//  WebClipper
//
//  Created by Daniel Braun on 01/04/07.
//  Copyright 2007 Daniel Braun http://page-appart.net, http://braun.daniel.free.fr All rights reserved.
//

#import "CalendarRange.h"
#import "StringExtension.h"

@implementation CalendarRange
- (void) dealloc {
	[date1 release];
	[date2 release];
	[super dealloc];
}

- (id) init {
	self = [super init];
	if (self != nil) {
		date1=[[NSCalendarDate date]retain];
		date2=[[NSCalendarDate date]retain];
	}
	return self;
}

- (id) initWithCoder:(NSCoder *) coder
{
	//self=[super initWithCoder:coder];
	self=[super init];
	if ([coder allowsKeyedCoding]) {
		date1=[[coder decodeObjectForKey:@"date1"]retain];
		date2=[[coder decodeObjectForKey:@"date2"]retain];
	}
	return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
	//[super encodeWithCoder:coder];
	if ( [coder allowsKeyedCoding] ) {
		[coder encodeObject:date1 forKey:@"date1"];
		[coder encodeObject:date2 forKey:@"date2"];
	}
}

- (NSString *) description;
{
	return [NSString stringWithFormat:@"%@ ... %@", date1, date2];
}

- (NSCalendarDate *) date1
{
	return date1;
}
- (void) setDate1:(NSCalendarDate*)d1
{
	NSAssert([d1 isKindOfClass:[NSCalendarDate class]], @"not aNSCalendarDate class");
	[date1 release];
	date1=[d1 retain];
}
- (NSCalendarDate *) date2
{
	return date2;
}
- (void) setDate2:(NSCalendarDate*)d2
{
	NSAssert([d2 isKindOfClass:[NSCalendarDate class]], @"not aNSCalendarDate class");
	[date2 release];
	date2=[d2 retain];
}

static NSArray *monthNames(void)
{
	static NSMutableArray *monthNames=nil;
	if (monthNames) return monthNames;
	
	monthNames=[[NSMutableArray arrayWithCapacity:48]retain];
	NSLocale *lc=[NSLocale currentLocale];
	NSLocale *le=[[[NSLocale alloc]initWithLocaleIdentifier:@"en"]autorelease];
	NSDateFormatter *f=[[[NSDateFormatter alloc]init]autorelease];
	[f setFormatterBehavior:NSDateFormatterBehavior10_4];
	//[f setDateStyle:NSDateFormatterMediumStyle];
	[f setLocale:lc];
	NSArray *a=[f monthSymbols];
	[monthNames addObjectsFromArray:a];
	a=[f shortMonthSymbols];
	[monthNames addObjectsFromArray:a];
	//NSLog(@"goty locals %@ / %@\n", [le objectForKey:NSLocaleLanguageCode], [lc objectForKey:NSLocaleLanguageCode]);
	if ([ [le objectForKey:NSLocaleLanguageCode] isEqualToString:[lc objectForKey:NSLocaleLanguageCode] ]) {
		//NSLog(@"ok");
	} else {
		[f setLocale:le];
		NSArray *a=[f monthSymbols];
		[monthNames addObjectsFromArray:a];
		a=[f shortMonthSymbols];
		[monthNames addObjectsFromArray:a];
	}
	[monthNames addObjectsFromArray:[NSArray arrayWithObjects:
		@"jan", @"fev", @"mar", @"avr", @"mai", @"jun", @"jul", @"aou", @"sep", @"oct", @"nov", @"dec", nil]];
	//NSLog(@"got monthlist %@\n", monthNames);
	return monthNames;
}

static NSArray *dayOfWeekNames(void)
{
	static NSMutableArray *dowNames=nil;
	if (dowNames) return dowNames;
	
	dowNames=[[NSMutableArray arrayWithCapacity:7*4]retain];
	NSLocale *lc=[NSLocale currentLocale];
	NSLocale *le=[[[NSLocale alloc]initWithLocaleIdentifier:@"en"]autorelease];
	NSDateFormatter *f=[[[NSDateFormatter alloc]init]autorelease];
	[f setFormatterBehavior:NSDateFormatterBehavior10_4];
	//[f setDateStyle:NSDateFormatterMediumStyle];
	[f setLocale:lc];
	NSArray *a=[f weekdaySymbols];
	[dowNames addObjectsFromArray:a];
	a=[f shortWeekdaySymbols];
	[dowNames addObjectsFromArray:a];
	//NSLog(@"goty locals %@ / %@\n", [le objectForKey:NSLocaleLanguageCode], [lc objectForKey:NSLocaleLanguageCode]);
	if ([ [le objectForKey:NSLocaleLanguageCode] isEqualToString:[lc objectForKey:NSLocaleLanguageCode] ]) {
		//NSLog(@"ok");
	} else {
		[f setLocale:le];
		a=[f weekdaySymbols];
		[dowNames addObjectsFromArray:a];
		a=[f shortWeekdaySymbols];
		[dowNames addObjectsFromArray:a];
	}
	[dowNames addObjectsFromArray:[NSArray arrayWithObjects:
		@"lun", @"mar", @"mer", @"jeu", @"ven", @"sam", @"dim", nil]];
	//NSLog(@"got monthlist %@\n", monthNames);
	return dowNames;
}

- (id) initWithNaturalLangageString:(NSString *)s
{
	//NSLog(@"initWithNaturalLangageString: \"%@\"\n", s);
	self=[super init];
	if (!self) return nil;
	int d1=-1;
	int d2=-1;
	int m1=-1;
	int m2=-1;
	int y1=-1;
	int y2=-1;
	BOOL noDay1=NO;
	BOOL singleMonth=NO;
	NSRange rg;

	s=[s lowercaseStringRemovingAccents];
	// Find month range
	NSRange rgmonth1;
	NSRange rgmonth2;
	BOOL havemonth;
	BOOL havemonth2=NO;
	int ma,mb;
	NSCalendarDate *now=[NSCalendarDate date];

	havemonth=[s findOneSubstring:monthNames() range:&rgmonth1 index:&ma];
	if (havemonth) {
		NSString *s2=[s substringFromIndex:rgmonth1.location+rgmonth1.length];
		havemonth2=[s2 findOneSubstring:monthNames() range:&rgmonth2 index:&mb];
		if (havemonth2) {
			if (rgmonth2.location>12) {
				// too far from month 1
				havemonth2=0;
			}
		}
		if (havemonth2) {
			m2=1+(mb % 12);
			m1=1+(ma % 12);
			NSString *afterMonth2=[s2 substringFromIndex:rgmonth2.location+rgmonth2.length];
			NSRange rgPossibleYear=[afterMonth2 firstNumberRange];
			if ((rgPossibleYear.length>=2) && (rgPossibleYear.length<=4) && (rgPossibleYear.location<8)) {
				y1=[[afterMonth2 substringWithRange:rgPossibleYear] intValue];
				//NSLog(@"possible year: %@\n", [afterMonth2 substringWithRange:rgPossibleYear]);
				if (y1<10) y1+=2000;
				else if (y1<100) y1+=1900;
				y2=y1;
			}
			NSString *sd1=[s substringToIndex:rgmonth1.location];
			NSRange rn1=[sd1 lastNumberRange];
			if (rn1.length) {
				d1=[[sd1 substringWithRange:rn1] intValue];
			}
			NSString *sd2=[s2 substringToIndex:rgmonth2.location];
			NSRange rn2=[sd2 lastNumberRange];
			if (rn2.length) {
				d2=[[sd2 substringWithRange:rn2] intValue];
			} 
		} else {
			// have single month. eg 10..19 fev, 20 fev 2007, 1 -> 30 apr 2007
			m2=1+(ma %12) ; m1=m2;
			NSString *beforeMonth=[s substringToIndex:rgmonth1.location];
			NSString *afterMonth=[s substringFromIndex:rgmonth1.location+rgmonth1.length];
			NSRange rgPossibleYear=[afterMonth firstNumberRange];
			if ((rgPossibleYear.length>=2) && (rgPossibleYear.length<=4) && (rgPossibleYear.location<8)) {
				if (0) NSLog(@"possible year: %@ (l%d)\n", [afterMonth substringWithRange:rgPossibleYear],
				      rgPossibleYear.length);
				y1=[[afterMonth substringWithRange:rgPossibleYear] intValue];
				if (y1<10) y1+=2000;
				else if (y1<100) y1+=1900;
				y2=y1;
			}
			NSRange rn2=[beforeMonth lastNumberRange];
			if (rn2.length) {
				NSString *ds2=[beforeMonth substringWithRange:rn2];
				d2=[ds2 intValue];
				// eg : 23 .. 24 Fev
				NSString *s3=[s substringToIndex:rn2.location];
				NSRange rn1=[s3 lastNumberRange];
				if (rn1.length) {
					NSString *ds1=[s3 substringWithRange:rn1];
					d1=[ds1 intValue];
					//NSLog(@"got  %@/%@\n", ds1, ds2);
				} else {
					noDay1=YES;
				}
			} else {
				// no day number, single month ?
				//or try day of week
				goto dayofweek;
				singleMonth=YES;
			}
		}
		if (-1==y2) {
			y2=[now yearOfCommonEra];
		}
		if (singleMonth) {
			// todo
			NSAssert(0, @"todo");
		}
		if (-1==m2) {
			m2=[now dayOfCommonEra];
		}
		if (-1==d2) {
			d2=1;
		}
		date2=[[NSCalendarDate dateWithYear:y2 month:m2 day:d2
					       hour:12 minute:0 second:0 timeZone:nil]retain];
		if (noDay1) date1=[date2 retain];
		else {
			if (-1==d1) d1=d2;
			if (-1==m1) m1=m2;
			if (-1==y1) y1=y2;
			date1=[[NSCalendarDate dateWithYear:y1 month:m1 day:d1
						       hour:12 minute:0 second:0 timeZone:nil]retain];
		}		
	} else {
dayofweek:
		date1=[[s possibleDate:&rg] retain];
		if (date1) {
			NSString *s2=[s substringFromIndex:rg.location+rg.length];
			date2=[[s2 possibleDate:NULL]retain];
			if (!date2) date2=[date1 retain];
		} else {
			//look for e.g. "dimanche 15"
			NSRange rg;
			BOOL haveweek=[s findOneSubstring:dayOfWeekNames() range:&rg 
						    index:&ma];
			if (!haveweek) goto failed;
				
			s=[s substringFromIndex:rg.location+rg.length];
			rg=[s firstNumberRange];
			if (!rg.length) goto failed;
			d1=[[s substringWithRange:rg]intValue];
			s=[s substringFromIndex:rg.location+rg.length];
			haveweek=[s findOneSubstring:dayOfWeekNames() range:&rg 
					       index:&ma];
			if (haveweek) {
				// eg lundi 14 .. mardi 15
				s=[s substringFromIndex:rg.location+rg.length];
				rg=[s firstNumberRange];
				if (rg.length) {
					d2=[[s substringWithRange:rg]intValue];
				}
			}
			if (-1==d2) d2=d1;
			m1=m2=[now monthOfYear];
			y1=y2=[now yearOfCommonEra];
			date2=[[NSCalendarDate dateWithYear:y2 month:m2 day:d2
						       hour:12 minute:0 second:0 timeZone:nil]retain];
			date1=[[NSCalendarDate dateWithYear:y1 month:m1 day:d1
						       hour:12 minute:0 second:0 timeZone:nil]retain];

		}
	}
	return self;
failed:
	[self dealloc];
	return nil;
}

+ (id) calendarRangeWithNaturalLangageString:(NSString *)s
{
	return [[[[self class]alloc]initWithNaturalLangageString:s]autorelease];
}
- (id) copyWithZone:(NSZone *)zone
{
	CalendarRange *copy = [[[self class] allocWithZone: zone] init];
	[copy setDate1:date1];
	[copy setDate2:date2];
	return copy;
}

- (NSString *) shortString
{
	NSDictionary *loc=[[NSUserDefaults standardUserDefaults]dictionaryRepresentation];
	if ([date1 yearOfCommonEra]==[date2 yearOfCommonEra]) {
		if ([date1 monthOfYear]==[date2 monthOfYear]) {
			return [NSString stringWithFormat:@"%d .. %d %@%@",
				[date1 dayOfMonth], [date2 dayOfMonth], 
				[date2 descriptionWithCalendarFormat:@"%b" locale:loc],
				([date2 yearOfCommonEra]==[[NSCalendarDate date]yearOfCommonEra]) ? 
						     @"" : [date2 descriptionWithCalendarFormat:@" %Y" locale:loc]];
		} else {
			return [NSString stringWithFormat:@"%d %@ .. %d %@%@",
				[date1 dayOfMonth], 
				[date1 descriptionWithCalendarFormat:@"%b" locale:loc],
				[date2 dayOfMonth], 
				[date2 descriptionWithCalendarFormat:@"%b" locale:loc],
				([date2 yearOfCommonEra]==[[NSCalendarDate date]yearOfCommonEra]) ? 
						     @"" : [date2 descriptionWithCalendarFormat:@" %Y" locale:loc]];
		}
	} else {
		return [NSString stringWithFormat:@"%d %@ %@ .. %d %@ %@",
			[date1 dayOfMonth], 
			[date1 descriptionWithCalendarFormat:@"%b" locale:loc],
			[date1 descriptionWithCalendarFormat:@"%Y" locale:loc],
			[date2 dayOfMonth], 
			[date2 descriptionWithCalendarFormat:@"%b" locale:loc],
			[date2 descriptionWithCalendarFormat:@"%Y" locale:loc]];
	}
}

+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
{
	//NSLog(@"isSelectorExcludedFromWebScript\n");
	if (aSelector==@selector(date1)) return NO;
	if (aSelector==@selector(date2)) return NO;
	if (aSelector==@selector(shortString)) return NO;
	return YES;
}

- (BOOL) containDate:(NSCalendarDate *)date
{
	if ([date1 compare:date]==NSOrderedDescending) return NO;
	if ([date2 compare:date]==NSOrderedAscending) return NO;
	return YES;
}

@end

@implementation NSCalendarDate (shortstring)
- (NSString *) shortString
{
	NSDictionary *loc=[[NSUserDefaults standardUserDefaults]dictionaryRepresentation];
	return [self descriptionWithCalendarFormat:@"%d %b" locale:loc];
}

@end
